package hypernexusSystem

import (
	"errors"
	"sync"
	"time"

	"github.com/panjf2000/ants/v2"
)

// ObjectFactory 定义对象工厂函数类型，用于创建新对象
type ObjectFactory func() interface{}

// ObjectReset 定义对象重置函数类型，用于重置对象状态
type ObjectReset func(interface{})

// ObjectPoolConfig 对象池配置
type ObjectPoolConfig struct {
	MaxSize        int           // 对象池最大容量
	ExpiryDuration time.Duration // 对象过期时间
	PreAlloc       bool          // 是否预分配对象
}

// ObjectPool 对象池接口
type ObjectPool interface {
	Get() (interface{}, error) // 获取对象
	Put(interface{}) error     // 归还对象
	Close()                    // 关闭对象池
}

// objectPoolImpl 对象池实现
type objectPoolImpl struct {
	pool           *ants.Pool    // ants协程池
	factory        ObjectFactory // 对象创建工厂
	reset          ObjectReset   // 对象重置函数
	objects        sync.Pool     // 对象存储池
	maxSize        int           // 最大对象数量
	currentSize    int           // 当前对象数量
	mutex          sync.Mutex    // 互斥锁
	cleaner        *time.Ticker  // 清理定时器
	expiryDuration time.Duration // 过期时间
}

// ObjectPoolSystem 对象池管理系统
type ObjectPoolSystem struct {
	pools     map[string]ObjectPool // 对象池映射表
	mutex     sync.RWMutex          // 读写锁
	isRunning bool                  // 系统运行状态
}

// NewObjectPoolSystem 创建对象池管理系统
func NewObjectPoolSystem() *ObjectPoolSystem {
	return &ObjectPoolSystem{
		pools:     make(map[string]ObjectPool),
		isRunning: true,
	}
}

// RegisterPool 注册对象池
func (s *ObjectPoolSystem) RegisterPool(name string, factory ObjectFactory, reset ObjectReset, config ObjectPoolConfig) error {
	s.mutex.Lock()
	defer s.mutex.Unlock()

	if !s.isRunning {
		return errors.New("对象池系统已关闭")
	}

	if _, exists := s.pools[name]; exists {
		return errors.New("对象池已存在")
	}

	// 创建对象池
	pool, err := newObjectPool(factory, reset, config)
	if err != nil {
		return err
	}

	s.pools[name] = pool
	return nil
}

// GetPool 获取对象池
func (s *ObjectPoolSystem) GetPool(name string) (ObjectPool, error) {
	s.mutex.RLock()
	defer s.mutex.RUnlock()

	if !s.isRunning {
		return nil, errors.New("对象池系统已关闭")
	}

	pool, exists := s.pools[name]
	if !exists {
		return nil, errors.New("对象池不存在")
	}

	return pool, nil
}

// GetObject 从指定对象池获取对象
func (s *ObjectPoolSystem) GetObject(name string) (interface{}, error) {
	pool, err := s.GetPool(name)
	if err != nil {
		return nil, err
	}

	return pool.Get()
}

// PutObject 归还对象到指定对象池
func (s *ObjectPoolSystem) PutObject(name string, obj interface{}) error {
	pool, err := s.GetPool(name)
	if err != nil {
		return err
	}

	return pool.Put(obj)
}

// DestroyPool 销毁指定对象池
func (s *ObjectPoolSystem) DestroyPool(name string) error {
	s.mutex.Lock()
	defer s.mutex.Unlock()

	if !s.isRunning {
		return errors.New("对象池系统已关闭")
	}

	pool, exists := s.pools[name]
	if !exists {
		return errors.New("对象池不存在")
	}

	pool.Close()
	delete(s.pools, name)
	return nil
}

// Shutdown 关闭对象池系统
func (s *ObjectPoolSystem) Shutdown() {
	s.mutex.Lock()
	defer s.mutex.Unlock()

	if !s.isRunning {
		return
	}

	s.isRunning = false

	// 关闭所有对象池
	for name, pool := range s.pools {
		pool.Close()
		delete(s.pools, name)
	}
}

// newObjectPool 创建新的对象池
func newObjectPool(factory ObjectFactory, reset ObjectReset, config ObjectPoolConfig) (ObjectPool, error) {
	if factory == nil {
		return nil, errors.New("对象工厂函数不能为空")
	}

	if config.MaxSize <= 0 {
		config.MaxSize = 1000 // 默认最大容量
	}

	if config.ExpiryDuration <= 0 {
		config.ExpiryDuration = 10 * time.Minute // 默认过期时间
	}

	// 创建ants协程池
	antsPool, err := ants.NewPool(config.MaxSize)
	if err != nil {
		return nil, err
	}

	pool := &objectPoolImpl{
		pool:           antsPool,
		factory:        factory,
		reset:          reset,
		maxSize:        config.MaxSize,
		expiryDuration: config.ExpiryDuration,
		currentSize:    0,
	}

	// 初始化对象池
	pool.objects.New = func() interface{} {
		pool.mutex.Lock()
		defer pool.mutex.Unlock()

		if pool.currentSize < pool.maxSize {
			pool.currentSize++
			return factory()
		}
		return nil
	}

	// 预分配对象
	if config.PreAlloc {
		pool.mutex.Lock()
		for i := 0; i < config.MaxSize; i++ {
			obj := factory()
			pool.objects.Put(obj)
			pool.currentSize++
		}
		pool.mutex.Unlock()
	}

	// 启动清理定时器
	pool.cleaner = time.NewTicker(config.ExpiryDuration / 2)
	go func() {
		for range pool.cleaner.C {
			pool.cleanExpiredObjects()
		}
	}()

	return pool, nil
}

// Get 从对象池获取对象
func (p *objectPoolImpl) Get() (interface{}, error) {
	obj := p.objects.Get()
	if obj == nil {
		p.mutex.Lock()
		if p.currentSize < p.maxSize {
			obj = p.factory()
			p.currentSize++
			p.mutex.Unlock()
		} else {
			p.mutex.Unlock()
			return nil, errors.New("对象池已满")
		}
	}
	return obj, nil
}

// Put 归还对象到对象池
func (p *objectPoolImpl) Put(obj interface{}) error {
	if obj == nil {
		return errors.New("不能归还空对象")
	}

	// 重置对象状态
	if p.reset != nil {
		p.reset(obj)
	}

	p.objects.Put(obj)
	return nil
}

// Close 关闭对象池
func (p *objectPoolImpl) Close() {
	p.cleaner.Stop()
	p.pool.Release()
}

// cleanExpiredObjects 清理过期对象
func (p *objectPoolImpl) cleanExpiredObjects() {
	p.mutex.Lock()
	defer p.mutex.Unlock()

	// 这里简单实现，实际应用中可能需要更复杂的过期策略
	if p.currentSize > p.maxSize/2 {
		// 计算需要释放的对象数量
		toRelease := p.currentSize - p.currentSize/2

		// 由于sync.Pool没有直接清空的方法，我们可以通过以下方式释放对象：
		// 1. 创建一个临时存储
		tempObjects := make([]interface{}, 0, toRelease)

		// 2. 从池中获取对象并丢弃，不再放回池中
		for i := 0; i < toRelease; i++ {
			obj := p.objects.Get()
			if obj == nil {
				break // 池中已经没有对象了
			}

			// 如果需要特殊的资源释放，可以在这里处理
			// 例如关闭连接、释放文件句柄等

			// 将对象添加到临时存储，防止被GC回收（如果需要的话）
			tempObjects = append(tempObjects, obj)
		}

		// 3. 更新计数器
		p.currentSize = p.currentSize - len(tempObjects)

		// 4. 清空临时存储，允许GC回收这些对象
		tempObjects = nil
	}
}
